using System;
using System.Collections.Generic;
using System.Text;

namespace WindowsApplication1
{
  public class Vector
  {
    private double[] m_elements;

    public Vector(uint dimensions)
    {
      m_elements = new double[dimensions];
    }

    public int Length
    {
      get { return m_elements.Length; }
    }

    public double[] Elements
    {
      get { return m_elements; }
    }

    static public double Distance(Vector a, Vector b)
    {
      if (a.Length != b.Length)
        return 0.0;

      double sum = 0.0;
      for (int i = 0; i < a.Length; i++)
      {
        sum += (b.Elements[i] - a.Elements[i]) * (b.Elements[i] - a.Elements[i]);
      }

      return Math.Sqrt(sum);
    }

    static public Vector operator +(Vector a, Vector b)
    {
      if (a.Length == b.Length)
      {
        Vector c = new Vector((uint)a.Length);
        for (int i = 0; i < a.Length; i++)
        {
          c.Elements[i] = a.Elements[i] + b.Elements[i];
        }
        return c;
      }
      return null;
    }

    public void Add(Vector v)
    {
      if (Length == v.Length)
      {
        for (int i = 0; i < Length; i++)
        {
          m_elements[i] += v.Elements[i];
        }
      }
    }

    public void Div(double d)
    {
      for (int i = 0; i < Length; i++)
      {
        m_elements[i] /= d;
      }
    }

  }


  public class Feature : IComparable<Feature>
  {
    private Vector m_element;
    
    private int m_featureClass;

    public Feature(uint dimensions, int featureClass)
    {
      m_element = new Vector(dimensions);
      m_featureClass = featureClass;
    }

    public double[] Elements
    {
      get { return m_element.Elements; }
    }

    public int Class
    {
      get { return m_featureClass; }
      set { m_featureClass = value; }
    }

    public Vector Vector
    {
      get { return m_element; }
    }

    public int CompareTo(Feature f)
    {
      return Class.CompareTo(f.Class);
    }

    public override string ToString()
    {
      string s;
      s = "(";
      for (int i = 0; i < Elements.Length - 1; i++)
      {
        s += Elements[i].ToString() + ",";
      }
      s += Elements[Elements.Length - 1] + ") [" + m_featureClass + "]";

      return s;
    }

    
  }


   /////////////////////////////////////////////////
   /////////////////////////////////////////////////
  class FeatureSpace
  {

    private List<Feature> m_Features;
    private uint m_dimensions;

    public FeatureSpace(uint dimensions)
    {
      m_dimensions = dimensions;
      m_Features = new List<Feature>();
    }


    public List<Feature> Features
    {
      get { return m_Features; }
    }

    public void AddFeature(Feature feature)
    {
      m_Features.Add(feature);
    }

    public Feature GetFeature(int index)
    {
      return m_Features[index];
    }


    public int GetNumberOfClasses()
    {
      if (m_Features.Count == 0)
        return 0;

      m_Features.Sort();

      int count = 1;
      int relClass = m_Features[0].Class;

      for (int i = 0; i < m_Features.Count; i++)
      {
        if (relClass != m_Features[i].Class)
        {
          count++;
          relClass = m_Features[i].Class;
        }
      }

      return count;
    }

    public Feature[] GetCentersOfClasses()
    {
      if (m_Features.Count == 0)
        return null;

      int n = GetNumberOfClasses();

      Feature[] feature = new Feature[n];
      //m_Features.Sort();

      int count = 0;
      int relClass = m_Features[0].Class;
      feature[0] = new Feature(m_dimensions, m_Features[0].Class);

      int groupElements = 0;

      for (int i = 0; i < m_Features.Count; i++)
      {
        if (relClass != m_Features[i].Class) 
        {
          feature[count].Vector.Div(groupElements);
          groupElements = 0;
          count++;
          relClass = m_Features[i].Class;
          feature[count] = new Feature(m_dimensions, relClass);
          
        }
        feature[count].Vector.Add(m_Features[i].Vector);
        groupElements++;
      }

      feature[count].Vector.Div(groupElements);

      return feature;

    }
    public Vector GetCenterOfClass(int classNo)
    {
      
      Vector v = new Vector(m_dimensions);

      int count = 0;
      for (int i = 0; i < m_Features.Count; i++)
      { 
        Feature feature = m_Features[i];

        if (feature.Class == classNo)
        {
          v.Add(feature.Vector);
          count++;
        }
      }

      v.Div(count);

      return v;
    }


    public override string ToString()
    {
      string s = "";
      for (int i = 0; i < Features.Count; i++)
      {
        s += m_Features[i].ToString();
        s += "\n";
      }
      return s;
    }

  }
}
